/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*          http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <assert.h>
#include <string.h>

// this should be enough
static char buf[65536] = {};
static char code_buf[65536 + 128] = {}; // a little larger than `buf` 
static char buf1[65536] = {};//buf add "(unsigned long)"before num
static char *code_format =
"#include <stdio.h>\n"
"int main() { "
"  long result = %s; "
"  printf(\"%%ld\", result); "
"  return 0; "
"}";
int if_over_flow(char *buf){
	if(strlen(buf) + 1 <= 1000) return 0;
	return 1;
}
int choose (int max)
{
	//srand((unsigned int)time(NULL));
	int ret = rand()%max;
	return ret;
}
int gen_negative(char *buf,char *buf1 ){
	char negative[2] = {};
	negative[0] = '-';
	if(choose(2) == 1){
		if(if_over_flow(buf)) return 1;
		strcat(buf,negative);
		strcat(buf1,negative);
	} 
	return 0;
}
int gen_space(char*buf,char*buf1){
	char space[2]= {};
	space[0] = 32;
	for (int i =0;i<=choose(5);i++)
	{
		if(if_over_flow(buf)) return 1;
		strcat(buf,space);	
		strcat(buf1,space);
	}
	return 0;
}

int gen_unsigned(char *buf){
	if(if_over_flow(buf))return 1;
	char b[16] = "(unsigned long)";
	strcat(buf,b);
	return 0;	
}
int gen_num(char* buf,char *buf1)
{
int max_cnt = choose(10);
while(max_cnt == 0){max_cnt = choose(10);}
	for (int i= 0; i<max_cnt;i++)
	{
		char num;
		num = ((char)choose(10))+48;
		while((i == 0 && num == 48)){
			 num = ((char)choose(10))+48; 
		} 
		if(if_over_flow(buf) == 1){return 1;}
		strcat(buf,&num);
		strcat(buf1,&num);
		
	}
	return 0;
}
int gen(char a,char *buf,char*buf1){
	if (if_over_flow(buf)) return 1;
	char b[2] = {};
	b[0]= a;
	strcat(buf,b);
	return 0;
}
int  gen_rand_op(char* buf,char*buf1)
{
	if (if_over_flow(buf)) return 1;
	char a[2] = "+";
	char b[2] = "-";
	char c[2] = "*";
	char d[2] = "/";
	char e[3] = "==";
	char f[3] = "&&";
	int flag = choose(6);
	switch(flag){

		case 0: strcat(buf,a);strcat(buf1,a);break; 
		case 1:strcat(buf,b);strcat(buf1,b);break; 
		case 2:strcat(buf,c);strcat(buf1,c);break; 
		case 3:strcat(buf,d);strcat(buf1,d);break; 
		case 4:strcat(buf,e);strcat(buf1,e);break;
		case 5:strcat(buf,f);strcat(buf1,f);break;
		default:strcat(buf,a);strcat(buf1,a);break;
	}
	return 0;

}
static int  gen_rand_expr() {
if (if_over_flow(buf)) return 1;
int flag = choose(3);
if(gen_space(buf,buf1)== 1)return 1;
	switch(flag){
		case 0: 
			if(gen_unsigned(buf1)==1)return 1;
			if(gen_negative(buf,buf1)==1)return 1;
			if (gen_num(buf,buf1)==1)return 1;
			break;
    		case 1: 
			if(gen_negative(buf,buf1)==1)return 1;
			if(gen('(',buf,buf1)== 1) return 1;
			if( gen_rand_expr()==1) return 1;
			if( gen(')',buf,buf1)==1) return 1;
			 break;
    		default:if (gen_rand_expr()== 1)return 1;
			if( gen_rand_op(buf,buf1)==1)return 1;
			if( gen_rand_expr() == 1)return 1;
			 break;	
	}
if(gen_space(buf,buf1)==1)return 1;
return 0;
}

int main(int argc, char *argv[]) {
  int seed = time(0);
  srand(seed);
  int loop = 1;
  if (argc > 1) {
    sscanf(argv[1], "%d", &loop);
  }
  int i;
  for (i = 0; i < loop; i ++) {
    memset(buf,'\0',sizeof buf);
    memset(buf1,'\0',sizeof buf1);
    memset(code_buf,'\0',sizeof code_buf);
    
    while(1){
	int flag = 0;
	flag = gen_rand_expr();
	if(flag == 0) break;
	memset(buf,'\0',sizeof buf);
	memset(buf1,'\0',sizeof buf1);
    };
    sprintf(code_buf, code_format, buf);

    FILE *fp = fopen("/tmp/.code.c", "w");
    assert(fp != NULL);
    fputs(code_buf, fp);
    fclose(fp);

    int ret = system("gcc /tmp/.code.c -o /tmp/.expr");
    if (ret != 0) continue;

    fp = popen("/tmp/.expr", "r");
    assert(fp != NULL);

    long result;
    int if_div_zero = 0;// == 0 mean wrong expression; div zero;
    if_div_zero = fscanf(fp, "%ld", &result);
    pclose(fp);
    if(if_div_zero == 1){
	 printf("%ld %s\n", result, buf);
	// printf("%lu %s\n", result, buf1);
    }
  }
  return 0;
}
